using System;
using System.Windows.Forms;
using LaserTag.Infrastructure;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XNAGraffiti
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class XnaGraffitiGame : Game
    {
        GraphicsDeviceManager graphics;
        private FireGraffiti m_fireGraffiti;
        private PaintGraffiti m_paintGraffiti;
        private CrazyPaint m_crazyPaint;

        private DelegateDispatcher m_delegateDispatcher = new DelegateDispatcher();
        public GraffitiEffect Effect { get; set; }

        private Form m_gameForm;

        public XnaGraffitiGame()
        {
            m_gameForm = (Form)Control.FromHandle(Window.Handle);
            m_gameForm.ControlBox = false;
            m_gameForm.FormBorderStyle = FormBorderStyle.None;
            m_gameForm.Text = string.Empty;
            

            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.PreferredBackBufferWidth = 1024;
            graphics.PreferredBackBufferHeight = 768;
            graphics.MinimumPixelShaderProfile = ShaderProfile.PS_2_0;

            m_fireGraffiti = new FireGraffiti(this);
            m_paintGraffiti = new PaintGraffiti(this);
            m_crazyPaint = new CrazyPaint(this);

            Window.AllowUserResizing = true;
            IsMouseVisible = true;

            Effect = GraffitiEffect.Fire;

            graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
        }

        void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            e.GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage = RenderTargetUsage.PreserveContents;
        }

        public void SetScreen(Screen screen)
        {
            m_gameForm.WindowState = FormWindowState.Normal;
            if(screen != null)
            {
                m_gameForm.Width = screen.Bounds.Width;
                m_gameForm.Height = screen.Bounds.Height;
                m_gameForm.Top = screen.Bounds.Top;
                m_gameForm.Left = screen.Bounds.Left;
            }
            m_gameForm.WindowState = FormWindowState.Maximized;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();
        }

        public DelegateDispatcher DelegateDispatcher
        {
            get { return m_delegateDispatcher; }
            set { m_delegateDispatcher = value; }
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            m_crazyPaint.LoadContent();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            DelegateDispatcher.ProcessDelegateQueue();
            m_crazyPaint.Update(gameTime);
            base.Update(gameTime);
        }

        private Point? m_lastStartPoint;
        private Point? m_lastEndPoint;

        public void DrawLine(Point? startPoint, Point? endPoint)
        {
            m_lastStartPoint = startPoint;
            m_lastEndPoint = endPoint;
            switch (Effect)
            {
                case GraffitiEffect.Fire:
                    m_fireGraffiti.DrawLine(startPoint, endPoint);
                    break;
                case GraffitiEffect.Paint:
                    //m_paintGraffiti.DrawLine(startPoint, endPoint);
                    //m_crazyPaint.DrawLine(startPoint, endPoint);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice device = graphics.GraphicsDevice;

            device.Clear(Color.Black);

            m_paintGraffiti.Draw(gameTime);
            m_fireGraffiti.Draw(gameTime);
            m_crazyPaint.Draw(gameTime);

            if(Effect == GraffitiEffect.Paint)
            {
                m_crazyPaint.DrawLine(m_lastStartPoint, m_lastEndPoint);
                //m_lastStartPoint = null;
                //m_lastEndPoint = null;
            }
            
            // This will draw the particle system components.
            base.Draw(gameTime);
        }
    }
}
